package com.lex.security.component;

import com.lex.security.config.IgnoreUrlsConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import java.util.Collection;
import java.util.function.Supplier;

@Slf4j
@Component
public class CustomAuthorizetionManager implements AuthorizationManager<RequestAuthorizationContext> {

    @Autowired
    private IgnoreUrlsConfig ignoreUrlsConfig;

    private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();


    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
        Authentication auth = authentication.get();
        String requestUrl = object.getRequest().getRequestURI(); //获取请求路径
        //OPTION请求直接放行
        if(object.getRequest().getMethod().equals(HttpMethod.OPTIONS.toString())){
            return new AuthorizationDecision(true);
        }
        //白名单直接放行
        AntPathMatcher matcher = new AntPathMatcher(); //ant风格的路径匹配器
        for (String path : ignoreUrlsConfig.getUrls()) {
            if(matcher.match(path, requestUrl)){
                return new AuthorizationDecision(true);
            }
        }
        //所有权限必须经过认证
        boolean isAnonymous = auth != null && !this.trustResolver.isAnonymous(auth)
                && auth.isAuthenticated();
        if(!isAnonymous) {
            log.info("当前用户未登录");
            return new AuthorizationDecision(false);
        }
        Authentication authentication1 = SecurityContextHolder.getContext().getAuthentication();
        Collection<? extends GrantedAuthority> authorities = authentication1.getAuthorities();
        //遍历authorities，判断当前用户是否有权限访问该路径
        boolean ischecked = false;
        for (GrantedAuthority authority : authorities) {
            String[] split = authority.toString().split("@");
            String url = (contextPath + split[0]).replace(":id", "*");
            String method = split[1];
            //判断requestUrl是否和url相等，有特殊情况，/user/:id和/user/1是相等的
            if(matcher.match(url,requestUrl) && method.equals(object.getRequest().getMethod())){
                log.info("当前用户有权限访问该路径");
                ischecked = true;
                return new AuthorizationDecision(true);
            }
        }
        if (!ischecked) {
            return new AuthorizationDecision(false);
        }
        //通过上边的验证后默认是放行的
        return new AuthorizationDecision(true);
    }
}
